<html>
<head>
  <title>性能优化(5)-卡顿优化</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="YXBJ Windows/601935 (zh-CN, DDL); Windows/10.0.0 (Win64); EDAMVersion=V2;"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 10pt;
    }
  </style>
</head>
<body>
<a name="678"/>
<h1>性能优化(5)-卡顿优化</h1>

<div>
<span><div><h1><span style="font-size: 20pt;">性能优化(5)-卡顿优化</span></h1><div><span style="font-size: 18px; color: rgb(0, 0, 0); font-family: 宋体; font-weight: bold; line-height: 1.8;">本篇文章是码牛学院经网上整理收集给大家的性能优化全集，希望能帮助到各位同学</span></div><div style="margin:0px;padding:0px;background-color:transparent;clear:both;"></div><div><h2><span style="font-weight: bold; text-decoration: none;">1, 感知卡顿</span></h2><div><span style="font-weight: normal; text-decoration: none;">用户对卡顿的感知, 主要来源于界面的刷新. 而界面的性能主要是依赖于设备的UI渲染性能. 如果我们的UI设计过于复杂, 或是实现不够好, 设备又不给力, 界面就会像卡住了一样, 给用户卡顿的感觉.</span></div><h3><span style="font-weight: bold; text-decoration: none;">1.1 16ms原则</span></h3><div><span style="font-weight: normal; text-decoration: none;">在剖析卡顿的原因之前, 我们先来了解下Android中著名的&quot;16ms&quot;原则:</span></div><blockquote><div><span style="font-weight: normal; text-decoration: none;">Android系统每隔16ms会发出VSYNC信号重绘我们的界面(Activity).</span></div><div><span style="font-weight: normal; text-decoration: none;">为什么是16ms, 因为Android设定的刷新率是60FPS(Frame Per Second), 也就是每秒60帧的刷新率, 约合16ms刷新一次.</span></div></blockquote><div><span style="font-weight: normal; text-decoration: none;">就像是这样的:</span></div><div><span style="font-weight: normal; text-decoration: none;"><img src="性能优化(5)-卡顿优化_files/851999-feaaebea717ba97b.png" type="image/png" data-filename="851999-feaaebea717ba97b.png" height="195" style="margin:0px;padding:0px;border:0px;height:auto;max-width:100%;cursor:zoom-in;" width="528"/></span></div><div><span style="font-weight: normal; text-decoration: none;">16ms</span></div><div><span style="font-weight: normal; text-decoration: none;">这就意味着, 我们需要在16ms内完成下一次要刷新的界面的相关运算, 以便界面刷新更新. 然而, 如果我们无法在16ms内完成此次运算会怎样呢?</span></div><div><span style="font-weight: normal; text-decoration: none;">例如, 假设我们更新屏幕的背景图片, 需要24ms来做这次运算. 当系统在第一个16ms时刷新界面, 然而我们的运算还没有结束, 无法绘出图片. 当系统隔16ms再发一次VSYNC信息重绘界面时, 用户才会看到更新后的图片. 也就是说用户是32ms后看到了这次刷新(注意, 并不是24ms). 这就是传说中的丢帧(dropped frame):</span></div><div><span style="font-weight: normal; text-decoration: none;"><img src="性能优化(5)-卡顿优化_files/851999-1904e950165ab33d.png" type="image/png" data-filename="851999-1904e950165ab33d.png" height="254" style="margin:0px;padding:0px;border:0px;height:auto;max-width:100%;cursor:zoom-in;" width="528"/></span></div><div><span style="font-weight: normal; text-decoration: none;">dropped frame</span></div><div><span style="font-weight: normal; text-decoration: none;">丢帧给用户的感觉就是卡顿, 而且如果运算过于复杂, 丢帧会更多, 导致界面常常处于停滞状态, 卡到爆.</span></div><div><span style="font-weight: normal; text-decoration: none;">那么会有哪些常见的情况会导致运算超过16ms, 进而丢帧, 让用户觉得卡顿呢?</span></div><h2><span style="font-weight: bold; text-decoration: none;">2, 卡顿原因分析及处理</span></h2><div><span style="font-weight: normal; text-decoration: none;">一般来说, 会有以下几种情况导致卡顿这种性能问题, 我们逐一看下:</span></div><h3><span style="font-weight: bold; text-decoration: none;">2.1 过于复杂的布局</span></h3><div><span style="font-weight: normal; text-decoration: none;">上节有说, 界面性能取决于UI渲染性能. 我们可以理解为UI渲染的整个过程是由CPU和GPU两个部分协同完成的.</span></div><div><span style="font-weight: normal; text-decoration: none;">其中, CPU负责UI布局元素的Measure, Layout, Draw等相关运算执行. GPU负责</span><a href="https://link.jianshu.com/?t=https://zh.wikipedia.org/wiki/%E6%A0%85%E6%A0%BC%E5%8C%96" rel="nofollow" style="font-weight: normal; text-decoration: underline;" target="_blank">栅格化(rasterization)</a><span style="font-weight: normal; text-decoration: none;">, 将UI元素绘制到屏幕上.</span></div><div><span style="font-weight: normal; text-decoration: none;">如果我们的</span><span style="font-weight: bold; text-decoration: none;">UI布局层次太深</span><span style="font-weight: normal; text-decoration: none;">, 或是</span><span style="font-weight: bold; text-decoration: none;">自定义控件的onDraw中有复杂运算</span><span style="font-weight: normal; text-decoration: none;">, CPU的相关运算就可能大于16ms, 导致卡顿.</span></div><div><span style="font-weight: normal; text-decoration: none;">这个时候, 我们需要借助Hierarchy Viewer这个工具来帮我们分析布局了. Hierarchy Viewer不仅可以以</span><span style="font-weight: bold; text-decoration: none;">图形化树状结构</span><span style="font-weight: normal; text-decoration: none;">的形式展示出UI层级, 还对每个节点给出了三个小圆点, 以指示该元素Measure, Layout, Draw的耗时及性能.</span></div><div><span style="font-weight: normal; text-decoration: none;">具体请参考</span><a href="https://www.jianshu.com/p/4943dae4c333" style="font-weight: normal; text-decoration: underline;" target="_blank">App优化之Layout怎么摆</a><span style="font-weight: normal; text-decoration: none;">.</span></div><h3><span style="font-weight: bold; text-decoration: none;">2.2 过度绘制(Overdraw)</span></h3><div><span style="font-weight: normal; text-decoration: none;">上节说的CPU方面的, 关于GPU的绘制, 如果我们的界面存在Overdraw, 也可能导致卡顿.</span></div><blockquote><div><span style="font-weight: normal; text-decoration: none;">Overdraw: 用来描述一个像素在屏幕上多少次被重绘在一帧上.</span></div><div><span style="font-weight: normal; text-decoration: none;">通俗的说: 理想情况下, 每屏每帧上, 每个像素点应该只被绘制一次, 如果有多次绘制, 就是Overdraw, 过度绘制了.</span></div></blockquote><h4><span style="font-weight: bold; text-decoration: none;">2.2.1 调试Overdraw</span></h4><div><span style="font-weight: normal; text-decoration: none;">Android系统提供了可视化的方案来让我们很方便的查看overdraw的现象:</span></div><div><span style="font-weight: normal; text-decoration: none;">在&quot;系统设置&quot;--&gt;&quot;开发者选项&quot;--&gt;&quot;调试GPU过度绘制&quot;中开启调试:</span></div><div><span style="font-weight: normal; text-decoration: none;"><img src="性能优化(5)-卡顿优化_files/851999-6d08b87f39d6aa07.png" type="image/png" data-filename="851999-6d08b87f39d6aa07.png" height="282" style="margin:0px;padding:0px;border:0px;height:auto;max-width:100%;cursor:zoom-in;" width="477"/></span></div><div><span style="font-weight: normal; text-decoration: none;">toggle GPU overdraw</span></div><div><span style="font-weight: normal; text-decoration: none;">此时界面可能会有五种颜色标识:</span></div><div><span style="font-weight: normal; text-decoration: none;"><img src="性能优化(5)-卡顿优化_files/851999-cf8322c4d28294cf.png" type="image/png" data-filename="851999-cf8322c4d28294cf.png" height="324" style="margin:0px;padding:0px;border:0px;height:auto;max-width:100%;cursor:zoom-in;" width="286"/></span></div><div><span style="font-weight: normal; text-decoration: none;">overdraw indicator</span></div><ul><li><div><span style="font-weight: normal; text-decoration: none;">原色: 没有overdraw</span></div></li><li><div><span style="font-weight: normal; text-decoration: none;">蓝色: 1次overdraw</span></div></li><li><div><span style="font-weight: normal; text-decoration: none;">绿色: 2次overdraw</span></div></li><li><div><span style="font-weight: normal; text-decoration: none;">粉色: 3次overdraw</span></div></li><li><div><span style="font-weight: normal; text-decoration: none;">红色: 4次及4次以上的overdraw</span></div></li></ul><blockquote><div><span style="font-weight: normal; text-decoration: none;">一般来说, 蓝色是可接受的, 是性能优的.</span></div></blockquote><h4><span style="font-weight: bold; text-decoration: none;">2.2.2 Overdraw的分析处理</span></h4><div><span style="font-weight: normal; text-decoration: none;">上面有言, 所谓Overdraw, 就是在一个像素点上绘制了多次. 常见的就是:</span></div><ol><li><div><span style="font-weight: normal; text-decoration: none;">绘制了多重背景.</span></div></li><li><div><span style="font-weight: normal; text-decoration: none;">绘制了不可见的UI元素.</span></div></li></ol><div><span style="font-weight: normal; text-decoration: none;">还是以</span><a href="https://link.jianshu.com/?t=https://github.com/mingjunli/GithubApp" rel="nofollow" style="font-weight: normal; text-decoration: underline;" target="_blank">GithubApp</a><span style="font-weight: normal; text-decoration: none;">这个App的代码为例调试, 打开应用, 展示是这样的:</span></div><div><span style="font-weight: normal; text-decoration: none;"><img src="性能优化(5)-卡顿优化_files/851999-8df87b5e563ea181.png" type="image/png" data-filename="851999-8df87b5e563ea181.png" height="476" style="margin:0px;padding:0px;border:0px;height:auto;max-width:100%;cursor:zoom-in;" width="268"/></span></div><div><span style="font-weight: normal; text-decoration: none;">example-1</span></div><div><span style="font-weight: normal; text-decoration: none;">可以看到是中间列表这块overdraw比较严重. 查看代码发现:</span></div><div><span style="font-weight: normal; text-decoration: none;">fragment_trending_container.xml中ViewPager设置了背景:</span></div><div><span style="font-weight: normal; text-decoration: none;">&lt;</span><span style="font-weight: normal; text-decoration: none;">android.support.v4.view.ViewPager</span></div><div><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">android:id</span>=</span><span style="font-weight: normal; text-decoration: none;">&quot;@+id/view_pager&quot;</span></div><div><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">android:background</span>=</span><span style="font-weight: normal; text-decoration: none;">&quot;@color/md_white_1000&quot;</span></div><div><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">android:layout_width</span>=</span><span style="font-weight: normal; text-decoration: none;">&quot;match_parent&quot;</span></div><div><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">android:layout_height</span>=</span><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">&quot;match_parent&quot;</span>/&gt;</span></div><div><span style="font-weight: normal; text-decoration: none;">而ViewPager中的fragment又设置了背景:</span></div><div><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">&lt;?</span>xml version=</span><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">&quot;1.0&quot;</span> encoding=</span><span style="font-weight: normal; text-decoration: none;">&quot;utf-8&quot;</span><span style="font-weight: normal; text-decoration: none;">?&gt;</span></div><div><span style="font-weight: normal; text-decoration: none;">&lt;</span><span style="font-weight: normal; text-decoration: none;">android.support.v4.widget.SwipeRefreshLayout</span></div><div><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">xmlns:android</span>=</span><span style="font-weight: normal; text-decoration: none;">&quot;http://schemas.android.com/apk/res/android&quot;</span></div><div><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">android:id</span>=</span><span style="font-weight: normal; text-decoration: none;">&quot;@+id/refresh_layout&quot;</span></div><div><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">android:background</span>=</span><span style="font-weight: normal; text-decoration: none;">&quot;@color/md_white_1000&quot;</span></div><div><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">android:layout_width</span>=</span><span style="font-weight: normal; text-decoration: none;">&quot;match_parent&quot;</span></div><div><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">android:layout_height</span>=</span><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">&quot;match_parent&quot;</span>&gt;</span></div><div><br/></div><div><span style="font-weight: normal; text-decoration: none;">...</span></div><div><span style="font-weight: normal; text-decoration: none;">&lt;/</span><span style="font-weight: normal; text-decoration: none;">android.support.v4.widget.SwipeRefreshLayout</span></div><blockquote><div><span style="font-weight: normal; text-decoration: none;">完整代码请查看</span><a href="https://link.jianshu.com/?t=https://github.com/mingjunli/GithubApp" rel="nofollow" style="font-weight: normal; text-decoration: underline;" target="_blank">Github上源码</a><span style="font-weight: normal; text-decoration: none;">, 本文分析时commit截止到b01b5793.</span></div></blockquote><div><span style="font-weight: normal; text-decoration: none;">删除外层ViewPager的背景再看:</span></div><div><span style="font-weight: normal; text-decoration: none;"><img src="性能优化(5)-卡顿优化_files/851999-6e133a9f38f372ce.jpg" type="image/jpeg" data-filename="851999-6e133a9f38f372ce.jpg" height="444" style="margin:0px;padding:0px;border:0px;height:auto;max-width:100%;cursor:zoom-in;" width="268"/></span></div><div><span style="font-weight: normal; text-decoration: none;">example-2</span></div><div><span style="font-weight: normal; text-decoration: none;">可以发现中间列表区域已经不再是红色了, 但是也没有达到蓝色这个可以接受的层级. 这是因为我们的Activity默认情况下, theme会给window设置一个纯色的背景. 因为我们这里不想使用这个默认的背景,故而给layout加了一层背景, 导致了多重绘制背景.</span></div><blockquote><div><span style="font-weight: normal; text-decoration: none;">当然我们也可以自定义主题, 将theme的window background设置成我们想要的, 而不在布局中设置.</span></div></blockquote><div><span style="font-weight: normal; text-decoration: none;">可以通过如下方式去掉window的背景.</span></div><div><span style="font-weight: normal; text-decoration: none;">设置主题:</span></div><div><span style="font-weight: normal; text-decoration: none;">&lt;</span><span style="font-weight: normal; text-decoration: none;">item</span> <span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">name</span>=</span><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">&quot;android:windowBackground&quot;</span>&gt;</span>@null<span style="font-weight: normal; text-decoration: none;">&lt;/</span><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">item</span>&gt;</span></span></div><div><span style="font-weight: normal; text-decoration: none;">或是代码设置, 在onCreate中:</span></div><div><span style="font-weight: normal; text-decoration: none;">getWindow().setBackgroundDrawable(</span><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">null</span>);</span></div><div><span style="font-weight: normal; text-decoration: none;">此时我们看到的效果:</span></div><div><span style="font-weight: normal; text-decoration: none;"><img src="性能优化(5)-卡顿优化_files/851999-e771c6130f482b0e.jpg" type="image/jpeg" data-filename="851999-e771c6130f482b0e.jpg" height="442" style="margin:0px;padding:0px;border:0px;height:auto;max-width:100%;cursor:zoom-in;" width="268"/></span></div><div><span style="font-weight: normal; text-decoration: none;">example-3</span></div><div><span style="font-weight: normal; text-decoration: none;">已基本达到优化水平.</span></div><blockquote><div><span style="font-weight: normal; text-decoration: none;">以上旨在提供分析方法和思路.</span></div><div><span style="font-weight: normal; text-decoration: none;">Overdraw主要原因是背景的多重绘制, 或是不可见的View在背后绘制等, 但不仅限于此.</span></div></blockquote><h3><span style="font-weight: bold; text-decoration: none;">2.3 UI线程的复杂运算</span></h3><div><span style="font-weight: normal; text-decoration: none;">如</span><a href="https://www.jianshu.com/p/6d855e984b99" style="font-weight: normal; text-decoration: underline;" target="_blank">上文ANR相关分析</a><span style="font-weight: normal; text-decoration: none;">中就说到UI线程的复杂运算会造成UI无响应, 当然更多的是造成UI响应停滞, 卡顿.</span></div><div><span style="font-weight: normal; text-decoration: none;">产生ANR已经是卡顿的极致了, 具体分析可以参看</span><a href="https://www.jianshu.com/p/6d855e984b99" style="font-weight: normal; text-decoration: underline;" target="_blank">App优化之ANR详解</a><span style="font-weight: normal; text-decoration: none;">一文.</span></div><div><span style="font-weight: normal; text-decoration: none;">关于运算阻塞导致的卡顿的分析, 可以使用Traceview这个工具.</span></div><div><span style="font-weight: normal; text-decoration: none;">具体Traceview的介绍, 以及实战分析, 可以参考</span><a href="https://www.jianshu.com/p/98c1656a357a" style="font-weight: normal; text-decoration: underline;" target="_blank">App优化之提升你的App启动速度之理论基础</a><span style="font-weight: normal; text-decoration: none;">和</span><a href="https://www.jianshu.com/p/4f10c9a10ac9" style="font-weight: normal; text-decoration: underline;" target="_blank">App优化之提升你的App启动速度之实例挑战</a><span style="font-weight: normal; text-decoration: none;">.</span></div><div><span style="font-weight: normal; text-decoration: none;">在这里需要提下我们在</span><a href="https://www.jianshu.com/p/da2a4bfcba68" style="font-weight: normal; text-decoration: underline;" target="_blank">性能分析工具</a><span style="font-weight: normal; text-decoration: none;">中提到的StrictMode.</span></div><h3><span style="font-weight: bold; text-decoration: none;">2.3.1 StrictMode的使用</span></h3><div><span style="font-weight: normal; text-decoration: none;">StrictMode用来基于线程或VM设置一些策略, 一旦检测到策略违例, 控制台将输出一些警告，包含一个trace信息展示你的应用在何处出现问题.</span></div><div><span style="font-weight: normal; text-decoration: none;">通常用来检测主线程中的磁盘读写或网络访问等耗时操作.</span></div><div><span style="font-weight: normal; text-decoration: none;">在Application或是Activity的onCreate中开启StrictMode:</span></div><div><span style="font-weight: normal; text-decoration: none;">public</span> <span style="font-weight: normal; text-decoration: none;">void</span> <span style="font-weight: normal; text-decoration: none;">onCreate</span><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">()</span> {</span></div><div><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">if</span> (BuildConfig.DEBUG) {</span></div><div><span style="font-weight: normal; text-decoration: none;">// 针对线程的相关策略</span></div><div><span style="font-weight: normal; text-decoration: none;">StrictMode.setThreadPolicy(<span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">new</span> StrictMode.ThreadPolicy.Builder()</span></span></div><div><span style="font-weight: normal; text-decoration: none;">.detectDiskReads()</span></div><div><span style="font-weight: normal; text-decoration: none;">.detectDiskWrites()</span></div><div><span style="font-weight: normal; text-decoration: none;">.detectNetwork() <span style="font-weight: normal; text-decoration: none;">// or .detectAll() for all detectable problems</span></span></div><div><span style="font-weight: normal; text-decoration: none;">.penaltyLog()</span></div><div><span style="font-weight: normal; text-decoration: none;">.build());</span></div><div><span style="font-weight: normal; text-decoration: none;">// 针对VM的相关策略</span></div><div><span style="font-weight: normal; text-decoration: none;">StrictMode.setVmPolicy(<span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">new</span> StrictMode.VmPolicy.Builder()</span></span></div><div><span style="font-weight: normal; text-decoration: none;">.detectLeakedSqlLiteObjects()</span></div><div><span style="font-weight: normal; text-decoration: none;">.detectLeakedClosableObjects()</span></div><div><span style="font-weight: normal; text-decoration: none;">.penaltyLog()</span></div><div><span style="font-weight: normal; text-decoration: none;">.penaltyDeath()</span></div><div><span style="font-weight: normal; text-decoration: none;">.build());</span></div><div><span style="font-weight: normal; text-decoration: none;">}</span></div><div><span style="font-weight: normal; text-decoration: none;"><span style="font-weight: normal; text-decoration: none;">super</span>.onCreate();</span></div><div><span style="font-weight: normal; text-decoration: none;">}</span></div><blockquote><div><span style="font-weight: normal; text-decoration: none;">如果你的线程出了问题, 控制台会有警告输出, 可以定位到代码.</span></div><div><span style="font-weight: normal; text-decoration: none;">相对简单, 在此就不多废话了.</span></div><div><span style="font-weight: normal; text-decoration: none;">解决UI线程的耗时操作方案, 可以参考</span><a href="https://www.jianshu.com/p/6d855e984b99" style="font-weight: normal; text-decoration: underline;" target="_blank">ANR详解</a><span style="font-weight: normal; text-decoration: none;">里面说到的那些线程模式.</span></div></blockquote><h3><span style="font-weight: bold; text-decoration: none;">2.4 频繁的GC</span></h3><div><span style="font-weight: normal; text-decoration: none;">上面说的都是处理上的, CPU, GPU相关的. 实际上内存原因也可能会造成应用不流畅, 卡顿的.</span></div><blockquote><div><span style="font-weight: normal; text-decoration: none;">说到这, 想起当年配台式机的三大件(CPU, 内存, 显示器)了. 貌似分析App性能也是这几大件啊 :)</span></div></blockquote><div><span style="font-weight: normal; text-decoration: none;">为什么说频繁的GC会导致卡顿呢?</span></div><div><span style="font-weight: normal; text-decoration: none;">简而言之, 就是</span><span style="font-weight: bold; text-decoration: none;">执行GC操作的时候，任何线程的任何操作都会需要暂停，等待GC操作完成之后，其他操作才能够继续运行</span><span style="font-weight: normal; text-decoration: none;">, 故而如果程序频繁GC, 自然会导致界面卡顿.</span></div><blockquote><div><span style="font-weight: normal; text-decoration: none;">以下内容参考自</span><a href="https://link.jianshu.com/?t=https://www.youtube.com/watch?v=McAvq5SkeTk&amp;list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE&amp;index=70" rel="nofollow" style="font-weight: normal; text-decoration: underline;" target="_blank">Android Performance Patterns:Memory Churn and Performance</a><span style="font-weight: normal; text-decoration: none;">.</span> <span style="font-weight: bold; text-decoration: none;">需翻墙</span></div></blockquote><div><span style="font-weight: normal; text-decoration: none;">导致频繁GC有两个原因:</span></div><ul><li><div><span style="font-weight: normal; text-decoration: none;">内存抖动(Memory Churn), 即大量的对象被创建又在短时间内马上被释放.</span></div></li><li><div><span style="font-weight: normal; text-decoration: none;">瞬间产生大量的对象会严重占用Young Generation的内存区域, 当达到阀值, 剩余空间不够的时候, 也会触发GC. 即使每次分配的对象需要占用很少的内存，但是他们叠加在一起会增加Heap的压力, 从而触发更多的GC.</span></div></li></ul><div><span style="font-weight: normal; text-decoration: none;">这些GC操作可能会造成上面说到的丢帧, 如下:</span></div><div><span style="font-weight: normal; text-decoration: none;"><img src="性能优化(5)-卡顿优化_files/851999-42d7e05150c3d530.jpg" type="image/jpeg" data-filename="851999-42d7e05150c3d530.jpg" height="340" style="margin:0px;padding:0px;border:0px;height:auto;max-width:100%;cursor:zoom-in;" width="532"/></span></div><div><span style="font-weight: normal; text-decoration: none;">gc dropped frame</span></div><div><span style="font-weight: normal; text-decoration: none;">就会让用户感知到卡顿了.</span></div><div><span style="font-weight: normal; text-decoration: none;">一般来说瞬间大量产生对象一般是因为我们在代码的循环中new对象, 或是在onDraw中创建对象等. 所以说这些地方是我们尤其需要注意的...</span></div></div><div> </div></div><div><br/></div></span>
</div></body></html> 